import asyncio
from collections import defaultdict
from inspect import iscoroutinefunction
from typing import Set, Callable, Coroutine, Dict

from bald_spider.exceptions import ReceiverTypeError


class Subscriber:
    def __init__(self):
        self._subscribers: Dict[str,Set[Callable[...,Coroutine]]] = defaultdict(set)

    def subscribe(
            self,
            receiver: Callable[...,Coroutine],
            *,
            event: str
    ):
        if not iscoroutinefunction(receiver):
            raise ReceiverTypeError(f"{receiver.__qualname__} must be coroutine function")
        self._subscribers[event].add(receiver)

    def unsubscribe(self,
            receiver: Callable[...,Coroutine],
            *,
            event: str):
        self._subscribers[event].discard(receiver)

    async def notify(self, event: str, *args, **kwargs):
        for receiver in self._subscribers[event]:
            asyncio.create_task(receiver(*args, **kwargs))
